﻿namespace Numbrella.TaskSamples.PrimeNumbers
{
	using System;
	using System.Globalization;
	using System.Threading;
	using Numbrella.Core;

	public class Problem : ProblemImplementationBase<Task, ResultContents>
	{
		#region Fields

		private readonly ResultValidator resultValidator = new ResultValidator();
		
		private readonly long rangeStart;
		private readonly long rangeEnd;

		private long primeNumberCount;

		#endregion

		public Problem(long rangeStart, long rangeEnd, int taskCount, int taskEvaluationCount)
			: base("Prime numbers", "Calculate amount of prime numbers in the given range.", taskCount, taskEvaluationCount)
		{
			if (rangeEnd < rangeStart)
				throw new ArgumentException("Range start should be lesser than range end.");
			if (taskCount > rangeEnd - rangeStart + 1)
				throw new ArgumentException("You can't give more tasks than length of the range.");

			this.rangeStart = rangeStart;
			this.rangeEnd = rangeEnd;
		}

		public override IResultValidator<ResultContents> ResultValidator
		{
			get { return this.resultValidator; }
		}

		protected override Task CreateTaskForId(int id)
		{
			long step = (this.rangeEnd - this.rangeStart + 1) / TaskCount;
			long start = this.rangeStart + (id * step);
			long end = id == TaskCount - 1 ? this.rangeEnd : this.rangeStart + ((id + 1) * step) - 1;
			return new Task(start, end, id);
		}

		protected override void AccumulateResult(TaskResult<ResultContents> result)
		{
			Interlocked.Add(ref this.primeNumberCount, result.Contents.PrimeNumberCount);
		}

		protected override void OnProblemSolved(EventArgs e)
		{
			System.Windows.MessageBox.Show(
				String.Format(CultureInfo.CurrentCulture, "Prime number count in {0}..{1} range: {2}", this.rangeStart, this.rangeEnd, this.primeNumberCount), "Solution found!");
		}

		protected override TimeSpan GetTimeoutForTask(int taskId)
		{
			return TimeSpan.FromMinutes(1);
		}
	}
}
